<?php

class DateHelper {
	
	public static function makeExactDate($timestamp = NULL) {
		if($timestamp !== NULL) {
			return date('Y-m-d H:i:s', $timestamp);
		}
		return date('Y-m-d H:i:s');
	}
	
	public static function makeDate($timestamp = NULL) {
		if($timestamp !== NULL) {
			return date('Y-m-d H:i', $timestamp);
		}
		return date('Y-m-d H:i');
	}

	public static function normalizeDate($timestamp = NULL, $freq = 1440) {
		if($freq == 0) {
			return null;
		}

		$date = getdate($timestamp);
		$min = $date['hours'] * 60 + $date['minutes'];
		return $timestamp - ($min - intval($min / ($freq)) * $freq) * 60;
	}
	
	public static function previousDate($timestamp, $freq) {
		return self::makeDate($timestamp - $freq * 60);
	}

	public static function makePathDate($timestamp = NULL) {
		if($timestamp !== NULL) {
			return date('YmdHi', $timestamp);
		}
		return date('YmdHi');
	}
	
	public static function makePartitionDate($timestamp = NULL, $format = 'Ymd/Hi') {
		if($timestamp !== NULL) {
			return date($format, $timestamp);
		}
		return SpecialPartition::None;
	}

    public static function getDates($startDate, $endDate) {
        $allDates = array();
        $ts = strtotime($startDate);
        while($ts <= strtotime($endDate)) {
                $allDates[] = date('Y-m-d', $ts);
                    $ts += 1440 * 60;
                        
                }
        return $allDates;
    }

	public static function makeDateFromPartition($partition) {
		if (preg_match('/^([\d]{4})([\d]{2})([\d]{2})\/([\d]{2})([\d]{2})/', $partition, $m)) {
			return "{$m[1]}-{$m[2]}-{$m[3]} {$m[4]}:{$m[5]}:00";
		}
		else {
			return null;
		}
	}
	
    public static function weekFirstDay($time=null) {
        $time = ($time==null) ? time() : $time;
        return date('Y-m-d', $time-86400*(date('N',$time)-1));
    }

    public static function monthFirstDay($time=NULL) {
        return date('Y-m-d', mktime(0,0,0,date('n'),1,date('Y')));
    }

    public static function yearFirstDay() {
            return date('Y').'-01-01';
    }

	public static function getFreqencyList($date, $allFrequencies) {
		
		$time = strtotime($date);
		$hour = date('H', $time);
		$min  = date('i', $time);
		$offsetMin = $min + $hour * 60;
		
		$ret = array();
		foreach($allFrequencies as $freq) {
			if($offsetMin % $freq == 0) {
				$ret[] = $freq;
			}
		}

		return $ret;
	}

	private static function num2DateExp($num) {
		if($num == 0) {
			return 0;
		}

		$units = array(
			1440	=>	'day',
			60		=>	'hour',
			30		=>	'half-hour',
			15		=>	'quarter',
			1		=>	'minute',
		);

		foreach($units as $unit => $name) {
			if($num % $unit == 0 && abs($num) >= $unit) {
				return intval($num / $unit) . " $name";
			}
		}
	}

	private static function dateExp2Num($exp) {
		$units = array(
			'day'			=>	1440,
			'hour'			=>	60,
			'half-hour'		=>	30,
			'quarter'		=>	15,
			'minute'		=>	1,
		);

		if($exp == 0) {
			return 0;
		}

		if(preg_match('/([-\d]+)\s+(\S+)/', $exp, $outs)) {
			$num = intval($outs[1]);
			$unit = $outs[2];

			if($num == 0) {
				return 0;
			}
			elseif(!isset($units[$unit])) {
				return false;
			}
			else {
				return $num * $units[$unit];
			}
		}
		else {
			return false;
		}
	}

	public static function partition2Exp($partition) {
		$partitions = explode('/', $partition);
		if($partitions[0][0] == '{') {
			if(!preg_match('/^\{(.*?),\s+(\d+)\}$/', $partitions[0], $outs)) {
				return false;
			}

			$timeOffset = $outs[1];
			$timeLength = $outs[2];

			if(preg_match('/^[-\d]+$/', $timeOffset)) {
				$str = self::num2DateExp($timeOffset);
			}
			else {
				$str = $timeOffset;
			}

			$partitions[0] = "{" . $str . ', ' . self::num2DateExp($timeLength) . '}';
		}
		elseif($partitions[0] == SpecialPartition::None) {
			unset($partitions[0]);
		}
		else {
			$timeOffset = 0;
			$timeLength = 0;
		}

		return array(
			'timeOffset'	=>	$timeOffset,
			'timeLength'	=>	$timeLength,
			'exp'			=>	implode('/', $partitions),
		);
	}

	public static function exp2partition($exp) {
        $exp = trim($exp);
		$partitions = explode('/', $exp);
		foreach($partitions as $index => $partition) {
			if(trim($partition) === '') {
				unset($partitions[$index]);
			}
		}

		$partitions = array_values($partitions);

		if(isset($partitions[0]) && $partitions[0][0] == '{') {
			if(!preg_match('/^\{(.*?),\s+(.*?)\}$/', $partitions[0], $outs)) {
				return false;
			}

			$timeOffset = $outs[1];
			$timeLength = $outs[2];

			if(preg_match('/\d+\-\d+\-\d+/', $timeOffset)) {
				$time = strtotime($timeOffset);
				if($time === false) {
					return false;
				}
				$timeOffset = DateHelper::makeDate($time);
			}
			else {
				$timeOffset = self::dateExp2Num($timeOffset);
			}

			$timeLength = self::dateExp2Num($timeLength);

			if($timeOffset === false || $timeLength === false || $timeLength <= 0) {
				return false;
			}
			$partitions[0] = "{{$timeOffset}, {$timeLength}}";
		}
		elseif(!isset($partitions[0]) || $partitions[0] != SpecialPartition::None) {
			array_unshift($partitions, SpecialPartition::None);
		}

		return array(
			'timeOffset'	=>	$timeOffset,
			'timeLength'	=>	$timeLength,
			'partitions'	=>	implode('/', $partitions),
		);
	}
	
	public static function isFuzzyPartition($partition) {
		if((strpos($partition, '%') === false) && (strpos($partition, '_') === false)) {
			return false;
		}

		if($partition == SpecialPartition::None) {
			return false;
		}
		
		return true;
	}
	
	/*public static function getPartitionCount($datePartitions) {
		$i = 0;
		
		foreach ($datePartitions as $datePartition) {
			if(self::isFuzzyPartition($datePartition)) {
				$i++;
			}
		}
		return $i;
	}*/
	
	public static function parseFunctionPartition($functionCode, $taskDate, $taskFreqency) {
		if(is_array($functionCode)) {
			return $functionCode;
		}
		
		$functionCode .= "\n echo serialize(getDatePartitions('$taskDate', $taskFreqency));";
		$filePath = TMP_PATH . '/UserFunc.php';
		file_put_contents($filePath, "<?php\n $functionCode \n?>");

		$execOut = array();
		$execRet = 0;		
		exec("php $filePath", $execOut, $execRet);
		
		if($execRet === 0) {
			$datePartitions = unserialize($execOut[0]);
		}
		else {
			return false;
		}	
		
		if(!is_array($datePartitions)) {
			return false;
		}

		foreach ($datePartitions as &$datePartition) {
			$datePartition = str_replace('*', '%', $datePartition);
			$datePartition = str_replace('?', '_', $datePartition);
		}
		return array_unique($datePartitions);
	}
	
	public static function parseDatePartition($parsePartition, $baseDate, $resFreqency, $format) {
		if(is_array($parsePartition)) {
			return $parsePartition;
		}

		if($resFreqency == Frequency::None) {
			$parsePartition = preg_replace('/\{.*?\}/', SpecialPartition::None, $parsePartition);
			return array($parsePartition);
		}
		
		$allPartions = explode('/', $parsePartition);
			
		$datePartition = '';
		foreach ($allPartions as $onePartition) {
			$len = strlen($onePartition); 
			
			if($len > 0 && $onePartition[0] == '{' && $onePartition[$len - 1] == '}') {
				$datePartition = substr($onePartition, 1, $len - 2);
			}
		}
		
		if(strlen($datePartition) == 0) {
			return array($parsePartition);
		}
		
		$partition = explode(',', $datePartition);
		
		if($partition[1] < $resFreqency) {
			return false;
		}
		else if($partition[1] > $resFreqency) {
			$numPart = $partition[1] / $resFreqency;
			if(!is_int($numPart)) {
				return false;
			}
		}
		else {
			$numPart = 1;
		}
	
		if(preg_match('/(\d{4})-(\d{1,2})-(\d{1,2})\s(\d{1,2}):(\d{2})/'
			, $partition[0]) === 1) {			
			$startTime = strtotime($partition[0]);
		}
		else {
			$startTime = strtotime($baseDate) + $partition[0] * 60;
		}
		
		$startDate = self::normalizeDate($startTime, $resFreqency);	
		
		if(isset($partition[2])) {
			$startDate = self::normalizeDate($startDate, $partition[2]);
		}
				
		$parsedPartitioned = array();
		for($i = 0; $i < $numPart; $i++) {
			$parsedPartitioned[$i] = str_replace('{'.$datePartition.'}', 
				self::makePartitionDate($startDate + $i * $resFreqency * 60, $format), $parsePartition);
		}			
		return $parsedPartitioned;
	}
	
	public static function parseAutoCreatePeriod($baseDate, $autoCreatePeriod) {
		$taskTime = strtotime($baseDate);
		$autoCreatePeriod = unserialize($autoCreatePeriod);
		if($autoCreatePeriod['type'] == 'never') {
			$needRun = false;
		}
		else if($autoCreatePeriod['type'] == 'week') {
			$dayInWeek = date('w', $taskTime);
			if($dayInWeek == 0) {
				$dayInWeek = 7;
			}

			if($autoCreatePeriod['day'] == $dayInWeek) {
				$needRun = true;
			}
			else {
				$needRun = false;
			}
		}
		else if($autoCreatePeriod['type'] == 'month') {
			$dayInMonth = date('j', $taskTime);
			if($autoCreatePeriod['day'] == 0 && $dayInMonth == date('t', $taskTime)) {
				$needRun = true;
			}
			elseif($autoCreatePeriod['day'] == $dayInMonth) {
				$needRun = true;
			}
			else {
				$needRun = false;
			}
		}
		else {
			$needRun = true;
		}

        if ($needRun) {
            $beginTime = strtotime($autoCreatePeriod["beginDate"]);
            $curTime = strtotime($baseDate);
            $endTime = strtotime($autoCreatePeriod["endDate"]);
            if ($beginTime > 0 && $beginTime > $curTime) {
                $needRun = false;
            }
            if ($endTime > 0 && $curTime > $endTime) {
                $needRun = false;
            }
        }
        /*
        if($needRun && array_key_exists('beginDate', $autoCreatePeriod)
		&& array_key_exists('endDate', $autoCreatePeriod)
		&& !empty($autoCreatePeriod['beginDate'])
		&& !empty($autoCreatePeriod['endDate']) ) {
			if((strtotime($baseDate) >= strtotime($autoCreatePeriod['beginDate']))
			&& (strtotime($baseDate) <= strtotime($autoCreatePeriod['endDate']))) {
				$needRun = true;
			}
			else {
				$needRun = false;
			}
        }
        */
		return $needRun;
	}
	
	public static function parseDateInPath($path, $baseDate, $freq = 1440) {
		
		$time = strtotime($baseDate);
		$date = date('Ymd', $time);
		$today = date('Ymd', $time + 60 * 60 * 24);
		$year = date('Y', $time);
		$month= date('m', $time);
		$day = date('d', $time);
		$week = date('w', $time);
		$path = str_replace('{TODAY}', $today, $path);
		$path = str_replace('{DATE}', $date, $path);
		if(preg_match("/{DATE@(.*?)}/",$path,$out)){
			$path = str_replace($out[0],date("Ymd", strtotime((-$out[1])." days ago",$time)),$path);
		}
		$path = str_replace('{YEAR}', $year, $path);
		$path = str_replace('{MON}', $month, $path);
		$path = str_replace('{DAY}', $day, $path);
		$path = str_replace('{WEEK}', $week, $path);

		$step = 0;
		if(strstr($path, "{MINUTE}") !== false) {
			$step = 1;
		}
		elseif(strstr($path, "{QUARTER}") !== false) {
			$step = 15;
		}
		elseif(strstr($path, "{HALF}") !== false) {
			$step = 30;
		}
		elseif(strstr($path, "{HOUR}") !== false) {
			$step = 60;
		}
		elseif(strstr($path, "{APM}") !== false) {
			$step = 720;
		}

		if($step == 0) {
			return array($path);
		}
		else {
			$paths = array();
			for($i = 0; $i < $freq; $i += $step) {
				$time = strtotime($baseDate) + $i * 60;
				$hour = date('H', $time);
				$min = date('i', $time);
				if($min < 30) {
					$half = '00';
				}
				else {
					$half = '30';
				}

				if($min < 15) {
					$quarter = 0;
				}
				else if($min < 30) {
					$quarter = 1;
				}
				else if($min < 45) {
					$quarter = 2;
				}
				else {
					$quarter = 3;
				}

				$apm = date('a', $time);
				$paths[] = str_replace(
						array(
							'{HOUR}', 
							'{HALF}',
							'{QUARTER}',
							'{APM}',
							'{MINUTE}',
							),
						array(
							$hour, 
							$half,
							$quarter,
							$apm,
							$min,
							),
						$path
						);
			}
			return $paths;
		}
	}

}
